/*
 * @filename QueryResultsConversionTool.java
 * @author barry
 * @version 0.0.1
 * @date 2020年3月4日
 */
package com.bnzj.core.persistence.query;

import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.persistence.Entity;
import javax.persistence.Tuple;
import javax.persistence.TupleElement;

import com.bnzj.core.persistence.entity.BaseEntity;
import com.bnzj.core.persistence.query.conversion.CaseFormat;
import com.bnzj.core.util.BeanUtils;
import org.springframework.cglib.beans.BeanMap;

import lombok.extern.slf4j.Slf4j;

/**
 * 查询结果转换工具类
 * @author barry
 * @date 2020-03-04
 */
@Slf4j
public class QueryResultsConversionTool {
    
    public static void main(String[] args) {
        ParameterizedType ptype = (ParameterizedType)new HashMap<String, Object>().getClass().getGenericSuperclass();
        for(Type type : ptype.getActualTypeArguments()) {
            System.out.println(type.getTypeName());
        }
        BaseEntity.class.isAnnotationPresent(Entity.class);
        System.out.println(Map.class.isAssignableFrom(HashMap.class));
        for(Annotation annotation : BaseEntity.class.getAnnotations()) {
            System.out.println(annotation.annotationType());
        }
    }
    
    public static List<Map<String, Object>> tupleToMap(List<Tuple> tupleList){
        return tupleList.parallelStream().map(tupleToMap()).collect(Collectors.toList());
    }
    
    public static <T> List<T> tupleToBean(List<Tuple> tupleList, Class<T> clz){
        return tupleList.parallelStream().map(tupleToBean(clz)).filter(t -> t != null).collect(Collectors.toList());
    }
    
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    public static <R> Function<Tuple, R> tupleToBean(Class<R> clz){
        return tuple -> {
            try {
                return mapToBean(tupleToMap().apply(tuple), BeanUtils.instantiateClass(clz));
            } catch (Exception e) {
                log.warn(clz.getName(), e);
                return null;
            }
        };
    }

    public static <R> Function<Map<String, Object>, R> mapToBean(Class<R> clz){
        return map -> {
            try {
                return mapToBean(map, BeanUtils.instantiateClass(clz));
            } catch (Exception e) {
                log.warn(clz.getName(), e);
                return null;
            }
        };
    }
    
    public static Function<Tuple, Map<String, Object>> tupleToMap(){
        return tuple -> {
            Map<String, Object> map = new HashMap<String, Object>();
            for(TupleElement<?> element : tuple.getElements()) {
                String columnName = element.getAlias();
                columnName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, columnName);
                columnName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, columnName);
                Object value = tuple.get(element.getAlias());
                map.put(columnName, value);
                if(java.math.BigInteger.class.isAssignableFrom(element.getJavaType())) {
                    map.put(columnName, ((java.math.BigInteger)value).longValue());
                }
                if(Byte.class.isAssignableFrom(element.getJavaType())) {
                    map.put(columnName, ((Byte)value).shortValue());
                }
            }
            return map;
        };
    }
}
